﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Reflection;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Extensions;

namespace zijian666.Converts.Core;

/// <summary>
/// 用于实现任何对象的键值对循环
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
public struct KeyValueEnumerator<TKey, TValue>
{
    // 用于操作 NameObjectCollectionBase 中的 BaseGetKey 方法
    private static readonly Func<NameObjectCollectionBase, int, string> BaseGetKeyHandler =
        (Func<NameObjectCollectionBase, int, string>)typeof(NameObjectCollectionBase).GetMethod("BaseGetKey", BindingFlags.Instance | BindingFlags.NonPublic).CreateDelegate(typeof(Func<NameObjectCollectionBase, int, string>));

    // 用于操作 NameObjectCollectionBase 中的 BaseGet 方法
    private static readonly Func<NameObjectCollectionBase, int, object> BaseGetHandler =
        (Func<NameObjectCollectionBase, int, object>)typeof(NameObjectCollectionBase).GetMethod("BaseGet", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(int) }, null).CreateDelegate(typeof(Func<NameObjectCollectionBase, int, object>));

    // 可循环对象
    private readonly IEnumerator? _enumerator;
    // 当前操作对象
    private readonly object _object;
    // 对象类型枚举
    private readonly ObjectType _type;
    // 转换上下文
    private readonly IConvertContext _context;
    // 键的类型转换器
    private readonly IConvertor<TKey>? _keyConvertor;
    // 值的类型转换器
    private readonly IConvertor<TValue>? _valueConvertor;
    // 循环下标
    private int _index;
    /// <summary>
    /// 当前对象的Key的个数
    /// </summary>
    public int Count { get; }

    /// <summary>
    /// 用于描述对象的类型的枚举
    /// </summary>
    private enum ObjectType
    {
        /// <summary>
        /// 未知类型
        /// </summary>
        Undefined = 0,
        /// <summary>
        /// <seealso cref="IDataReader"/> 类型
        /// </summary>
        DataReader,
        /// <summary>
        /// <seealso cref="IDataRecord"/> 类型
        /// </summary>
        DataRecord,
        /// <summary>
        /// <seealso cref="System.Data.DataRow"/> 类型
        /// </summary>
        DataRow,
        /// <summary>
        /// <seealso cref="System.Data.DataTableCollection"/> 类型
        /// </summary>
        DataTableCollection,
        /// <summary>
        /// <seealso cref="System.Data.DataTable"/> 类型
        /// </summary>
        DataTable,
        /// <summary>
        /// <seealso cref="IDictionary"/> 类型
        /// </summary>
        Dictionary,
        /// <summary>
        /// <seealso cref="IEnumerator"/> 类型
        /// </summary>
        Enumerator,
        /// <summary>
        /// <seealso cref="IDictionary{TKey, TValue}"/> 类型
        /// </summary>
        DictionaryT,
        /// <summary>
        /// <seealso cref="IEnumerable{T}"/> 类型
        /// </summary>
        EnumeratorT,
        /// <summary>
        /// <seealso cref="NameObjectCollectionBase"/> 类型
        /// </summary>
        NameObjectCollection,
        /// <summary>
        /// <seealso cref="System.Collections.Specialized.NameValueCollection"/> 类型
        /// </summary>
        NameValueCollection,
        /// <summary>
        /// <seealso cref="Object"/> 类型
        /// </summary>
        Object,
        /// <summary>
        /// <seealso cref="IDataReader"/> 类型
        /// </summary>
        Single,
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="context">转换上下文</param>
    /// <param name="input">操作对象</param>
    public KeyValueEnumerator(IConvertContext context, object input)
    {
        _context = context;
        _keyConvertor = typeof(TKey) == typeof(object) ? null : context.GetConvertor<TKey>();
        _valueConvertor = typeof(TValue) == typeof(object) ? null : context.GetConvertor<TValue>();

        _type = ObjectType.Undefined;
        _index = -1;
        _enumerator = null;
        _object = input;
        KeyIsString = false;

        switch (input)
        {
            case NameValueCollection nameValueCollection:
                _type = ObjectType.NameValueCollection;
                KeyIsString = true;
                Count = nameValueCollection.Count;
                break;
            case NameObjectCollectionBase nameObjectCollection:
                _type = ObjectType.NameObjectCollection;
                KeyIsString = true;
                Count = nameObjectCollection.Count;
                break;
            case DataRowView rowView:
                _object = rowView.Row;
                _type = ObjectType.DataRow;
                KeyIsString = true;
                Count = rowView.Row.Table.Columns.Count;
                break;
            case DataRow row:
                _type = ObjectType.DataRow;
                KeyIsString = true;
                Count = row.Table.Columns.Count;
                break;
            case DataSet dataSet:
                _object = dataSet.Tables;
                _type = ObjectType.DataTableCollection;
                KeyIsString = true;
                Count = dataSet.Tables.Count;
                break;
            case DataTableCollection tables:
                _object = tables;
                _type = ObjectType.DataTableCollection;
                KeyIsString = true;
                Count = tables.Count;
                break;
            case DataView dataView:
                _object = dataView.ToTable();
                _type = ObjectType.DataTable;
                Count = ((DataTable)_object).Rows.Count;
                break;
            case DataTable table:
                _type = ObjectType.DataTable;
                Count = table.Rows.Count;
                break;
            case IDataReader:
                _type = ObjectType.DataReader;
                Count = -1;
                break;
            case IDataRecord record:
                _type = ObjectType.DataRecord;
                KeyIsString = true;
                Count = record.FieldCount;
                break;
            case IDictionary<TKey, TValue> dict:
                _enumerator = dict.Keys.GetEnumerator();
                _type = ObjectType.DictionaryT;
                KeyIsString = typeof(TKey) == typeof(string);
                Count = dict.Count;
                break;
            case IDictionary dict:
                _enumerator = dict.Keys.GetEnumerator();
                _type = ObjectType.Dictionary;
                KeyIsString = typeof(TKey) == typeof(string);
                Count = dict.Count;
                break;
            case IEnumerable<TValue> enumerable:
                _enumerator = enumerable.GetEnumerator();
                _type = ObjectType.EnumeratorT;
                Count = -1;
                break;
            case IListSource listSource:
                var list = listSource.GetList();
                _enumerator = list.GetEnumerator();
                _type = ObjectType.Enumerator;
                Count = list.Count;
                break;
            case IEnumerable enumerable:
                if (input is string)
                {
                    goto default;
                }
                _enumerator = enumerable.GetEnumerator();
                _type = ObjectType.Enumerator;
                Count = -1;
                break;
            case IEnumerator<TValue> enumerator:
                _enumerator = enumerator;
                _type = ObjectType.EnumeratorT;
                Count = -1;
                break;
            case IEnumerator enumerator:
                _enumerator = enumerator;
                _type = ObjectType.Enumerator;
                Count = -1;
                break;
            default:
                if (input is TValue && typeof(TValue) != typeof(object))
                {
                    _type = ObjectType.Single;
                    Count = 1;
                }
                else
                {
                    var inputType = input.GetType();
                    if (inputType.IsSystemType())
                    {
                        _type = ObjectType.Single;
                        Count = 1;
                    }
                    else
                    {
                        _type = ObjectType.Object;
                        KeyIsString = true;
                        var properties = PropertyHelper.GetByType(inputType);
                        _enumerator = ((IEnumerable<PropertyHandler>)properties).GetEnumerator();
                        Count = properties.Count == 0 ? -2 : properties.Count;
                    }
                }
                break;
        }
    }

    /// <summary>
    /// 检查是否可以继续循环
    /// </summary>
    public bool MoveNext()
    {
        var next = _type switch
        {
            ObjectType.DataReader => ((IDataReader)_object).Read(),
            _ when _enumerator is not null => _enumerator.MoveNext(),
            _ => Count > 0 && _index + 1 < Count,
        };

        if (next)
        {
            _index++;
        }
        return next;
    }

    /// <summary>
    /// 获取当次循环的键
    /// </summary>
    public ConvertResult<TKey> GetKey()
    {
        var key = OriginalKey;
        if (key is TKey t)
        {
            return new(t);
        }
        if (_keyConvertor is null)
        {
            return ExceptionHelper.CantBuildConvertor(typeof(TKey).GetFriendlyName(), nameof(ResourceStrings.CONVERTOR_NOT_FOUND), _context.Settings.CultureInfo);
        }
        return _keyConvertor.Convert(_context, key);
    }

    /// <summary>
    /// 获取当此循环的原始键
    /// </summary>
    public object? OriginalKey => _type switch
    {
        ObjectType.DataRecord => ((IDataRecord)_object).GetName(_index) ?? "column" + _index,
        ObjectType.DataRow => ((DataRow)_object).Table.Columns[_index].ColumnName ?? "column" + _index,
        ObjectType.DataTableCollection => ((DataTableCollection)_object)[_index].TableName ?? "table" + _index,
        ObjectType.Enumerator => _index,
        ObjectType.EnumeratorT => _index,
        ObjectType.DataTable => _index,
        ObjectType.DataReader => _index,
        ObjectType.NameObjectCollection => BaseGetKeyHandler((NameObjectCollectionBase)_object, _index),
        ObjectType.NameValueCollection => ((NameValueCollection)_object).Keys[_index],
        ObjectType.Dictionary => _enumerator!.Current,
        ObjectType.DictionaryT => _enumerator!.Current,
        ObjectType.Object => ((PropertyHandler)_enumerator!.Current).Name,
        ObjectType.Single => 0,
        _ => throw new NotImplementedException(),
    };

    /// <summary>
    /// 获取当此循环的值
    /// </summary>
    public ConvertResult<TValue> GetValue()
    {
        switch (_type)
        {
            case ObjectType.DataRecord:
            case ObjectType.DataReader:
                var result = ((IDataRecord)_object).GetValue<TValue>(_index);
                if (result.Success || _valueConvertor is null)
                {
                    return result;
                }
                return _valueConvertor.Convert(_context, OriginalValue);
            default:
                var value = OriginalValue;
                if (value is TValue t)
                {
                    return new(t);
                }
                if (_valueConvertor is null)
                {
                    return ExceptionHelper.CantBuildConvertor(typeof(TValue).GetFriendlyName(), nameof(ResourceStrings.CONVERTOR_NOT_FOUND), _context.Settings.CultureInfo);
                }
                return _valueConvertor.Convert(_context, value);
        }
    }

    /// <summary>
    /// 获取当此循环的原始值
    /// </summary>
    public object? OriginalValue => _type switch
    {
        ObjectType.DataRecord => ((IDataRecord)_object).GetValue(_index),
        ObjectType.DataRow => ((DataRow)_object)[_index],
        ObjectType.DataTableCollection => ((DataTableCollection)_object)[_index],
        ObjectType.Enumerator => _enumerator!.Current,
        ObjectType.EnumeratorT => _enumerator!.Current,
        ObjectType.DataTable => ((DataTable)_object).Rows[_index],
        ObjectType.DataReader => _object,
        ObjectType.NameObjectCollection => BaseGetHandler((NameObjectCollectionBase)_object, _index),
        ObjectType.NameValueCollection => ((NameValueCollection)_object)[_index],
        ObjectType.Dictionary => ((IDictionary)_object)[_enumerator!.Current],
        ObjectType.DictionaryT => ((IDictionary<TKey, TValue>)_object)[((IEnumerator<TKey>)_enumerator!).Current],
        ObjectType.Object => ((PropertyHandler)_enumerator!.Current).GetValue(_object, _context.Settings.ReflectCompiler),
        ObjectType.Single => _object,
        _ => throw new NotImplementedException(),
    };

    /// <summary>
    /// 可循环数量不确定
    /// </summary>
    public bool DynamicCount => Count == -1;
    /// <summary>
    /// 不可循环
    /// </summary>
    public bool NotEnumerator => Count == -2;
    /// <summary>
    /// Key是否是字符串类型的
    /// </summary>
    public bool KeyIsString { get; }
}
